#include "TextServiceImpl.h"

#include <xml/Stream.h>
#include <text/Lookup.h>
#include <system/assert.h>

ARELLO_GAME_NAMESPACE_DECL_START

class PhraseLoader
	: public xml::ObjectUnicode
{
public:
	PhraseLoader()
		: target(0)
		, object(0)
	{ }

	void SetTarget(std::map<liba::Atom, std::wstring>& value)
	{
		this->target = &value;
	}
public: // xml::ObjectUnicode
	virtual bool on_attribute(xml::Provider * prov, const std::wstring & name, const std::wstring & value)
	{
		if (name == L"Name")
		{
			liba::Atom valueAtom(std::string(value.begin(), value.end()));
			std::pair<std::map<liba::Atom, std::wstring>::iterator, bool> insertResult =
				this->target->insert(std::make_pair(valueAtom, std::wstring()));

			if (!insertResult.second)
			{
				LIBA_FAIL("Duplicate phrase name");
				return false;
			}
			
			this->object = &insertResult.first->second;
			return true;		
		}

		if (name == L"Value")
		{
			if (!this->object)
			{
				LIBA_FAIL("Name attribute is missing");
				return false;
			}

			*this->object = value;
			return true;
		}

		return false;
	}
private:
	std::map<liba::Atom, std::wstring>* target;
	std::wstring* object;
};

template<typename T, typename NextTraits>
class HierarchyLoader
	: public xml::ObjectUnicode
{
public:
	HierarchyLoader()
		: target(0)
		, object(0)
	{ }

	void SetTarget(std::map<liba::Atom, T>& value)
	{
		this->target = &value;
	}
public:
	virtual bool on_node(xml::Provider * prov, const std::wstring & name)
	{
		if (!object)
		{
			LIBA_FAIL("Name attribute was missing");
			return false;
		}

		if (name == NextTraits::Name())
		{
			typename NextTraits::Loader loader;
			loader.SetTarget(this->object->data);
			
			return prov->parse_object(&loader);
		}

		return false;
	}

	virtual bool on_attribute(xml::Provider * prov, const std::wstring & name, const std::wstring & value)
	{
		if (!target)
		{
			LIBA_FAIL("Nobody cared about setting target");
			return false;
		}

		if (name == L"Name")
		{
			liba::Atom valueAtom(std::string(value.begin(), value.end()));
			std::pair<typename std::map<liba::Atom, T>::iterator, bool> insertResult =
				this->target->insert(std::make_pair(valueAtom, T()));
		
			this->object = &insertResult.first->second;
			return true;
		}

		return false;
	}
private:
	std::map<liba::Atom, T>* target;
	T* object;
};

TextServiceImpl::TextServiceImpl()
{
	liba::text::SetDictionary(this);
}

TextServiceImpl::~TextServiceImpl()
{ } 

namespace {

struct PhraseTraits
{
	typedef PhraseLoader Loader;
	static const wchar_t* Name() { return L"Phrase"; }
};

struct SectionTraits
{
	typedef HierarchyLoader<Section, PhraseTraits> Loader;
	static const wchar_t* Name() { return L"Section"; }
};

}

bool TextServiceImpl::ReadFrom(liba::resource::Resource* r)
{
	HierarchyLoader<Chapter, SectionTraits> loader;
	loader.SetTarget(this->data);

	return xml::StreamResource(r).load(&xml::Root(&loader, "Chapter"));
}

const std::wstring& TextServiceImpl::DoGetText(
		const liba::Atom& chapter, 
		const liba::Atom& section,
		const liba::Atom& id)
{
	static std::wstring stringNotFound(L"--- Not Found ---");

	std::map<liba::Atom, Chapter>::const_iterator chapterIter =
		this->data.find(chapter);

	if (chapterIter == this->data.end())
	{
		LIBA_FAIL("Chapter not found");	
		return stringNotFound;
	}
		
	const std::map<liba::Atom, Section>& sections =
		chapterIter->second.data;

	std::map<liba::Atom, Section>::const_iterator sectionIter =
		sections.find(section);

	if (sectionIter == sections.end())
	{
		LIBA_FAIL("Section not found");
		return stringNotFound;
	}

	const std::map<liba::Atom, std::wstring>& phrases =
		sectionIter->second.data;

	std::map<liba::Atom, std::wstring>::const_iterator phraseIter =
		phrases.find(id);

	if (phraseIter == phrases.end())
	{
		LIBA_FAIL("Phrase not found");
		return stringNotFound;
	}

	return phraseIter->second;
}

ARELLO_GAME_NAMESPACE_DECL_END